<?php
final class Mysql{
	
	//配置
	private $config = null;
	
	//数据库连接句柄
	private $link = null;
	
	//最后查询资源
	private $lastqueryid = null;
	
	//统计查询次数
	private $querycount = 0;
	
	/*
	 * 打开数据库连接，判断是否自动连接
	 */
	public function open($config){
		$this->config = $config;
		if($config['autoconnect'] == 1){
			$this->connect();
		}
	}
	
	/*
	 * 数据库连接
	 */
	private function connect(){
		$fun = $this->config['pconnect'] == 1 ? 'mysql_pconnect' : 'mysql_connect';	
		if(!$this->link = @$fun($this->config['hostname'],$this->config['username'], $this->config['password'], 1)){
			$this->halt('Can not connect to MySQL server');
			return false;
		}
		//设置编码
		if($this->version() > '4.1') {
			$charset = isset($this->config['charset']) ? $this->config['charset'] : '';
			$serverset = $charset ? "character_set_connection='$charset',character_set_results='$charset',character_set_client=binary" : '';
			$serverset .= $this->version() > '5.0.1' ? ((empty($serverset) ? '' : ',')." sql_mode='' ") : '';
			$serverset && mysql_query("SET $serverset", $this->link);		
		}
		
		if($this->config['database'] && !@mysql_select_db($this->config['database'], $this->link)) {
			$this->halt('Cannot use database '.$this->config['database']);
			return false;
		}
		$this->database = $this->config['database'];
		return $this->link;
	}
	
	/*
	 * 执行查询
	 */
	private function execute($sql){
		if(!is_resource($this->link)){
			$this->connect();
		}
		$this->lastqueryid = mysql_query($sql,$this->link) or $this->halt(mysql_error(), $sql);;		
		
		$this->querycount++;
		return $this->lastqueryid;
	}
	
	/*
	 * sql执行
	 */
	public function query($sql){
		return $this->execute($sql);
	}
	
	/*
	 * 遍历查询结果
	 */
	private function fetch_next($type = MYSQL_ASSOC){
		$res = mysql_fetch_array($this->lastqueryid,$type);
		if(!$res){
			$this->free_result();
		}	
		return $res;
	}
	
	/*
	 * 释放查询资源
	 */	
	private function free_result(){
		if(is_resource($this->lastqueryid)){
			mysql_free_result($this->lastqueryid);
			$this->lastqueryid = null;
		}
	}
	/**
	 * 查询
	 * @param $data 需要查询的字段值[例`name`,`gender`,`birthday`]
	 * @param $table 
	 * @param $where
	 * @param $limit
	 * @param $order
	 * @param $group
	 * @return unknown_type 查询结果集数组
	 */
	public function select($data, $table, $where = '', $limit = '', $order = '', $group = ''){
		$where = $where == '' ? '' : ' WHERE '.$where;
		$order = $order == '' ? '' : ' ORDER BY '.$order;
		$group = $group == '' ? '' : ' GROUP BY '.$group;
		$limit = $limit == '' ? '' : ' LIMIT '.$limit;
		
		$field = explode(',',$data);
		array_walk($field,array($this,'add_special_char'));
		$data = implode(',',$field);
		
		$sql = 'SELECT '.$data.' FROM `'.$this->config['database'].'`.`'.$table.'`'.$where.$group.$order.$limit;
		$this->execute($sql);
		
		$datalist = array();
		while(($rs = $this->fetch_next()) !== false){
				$datalist[] = $rs;
		}
		$this->free_result();
		return $datalist;

	}
	
/**
	 * 获取单条记录查询
	 * @param $data 		需要查询的字段值[例`name`,`gender`,`birthday`]
	 * @param $table 		数据表
	 * @param $where 		查询条件
	 * @param $order 		排序方式	[默认按数据库默认方式排序]
	 * @param $group 		分组方式	[默认为空]
	 * @return array/null	数据查询结果集,如果不存在，则返回空
	 */
	public function get_one($data, $table, $where = '', $order = '', $group = '') {
		$where = $where == '' ? '' : ' WHERE '.$where;
		$order = $order == '' ? '' : ' ORDER BY '.$order;
		$group = $group == '' ? '' : ' GROUP BY '.$group;
		$limit = ' LIMIT 1';
		$field = explode( ',', $data);
		array_walk($field, array($this, 'add_special_char'));
		$data = implode(',', $field);

		$sql = 'SELECT '.$data.' FROM `'.$this->config['database'].'`.`'.$table.'`'.$where.$group.$order.$limit;
		$this->execute($sql);
		$res = $this->fetch_next();
		$this->free_result();
		return $res;
	}
	
	/**
	 * 执行添加记录操作
	 * @param $data 		要增加的数据，参数为数组。数组key为字段值，数组值为数据取值
	 * @param $table 		数据表
	 * @return boolean
	 */
	public function insert($data, $table, $return_insert_id = false, $replace = false){
		if(!is_array( $data ) || $table == '' || count($data) == 0) {
			return false;
		}
		
		$fielddata = array_keys($data);
		$valuedata = array_values($data);
		//array_walk(),典型情况下 function 接受两个参数。array 参数的值作为第一个，键名作为第二个。如果提供了可选参数 userdata ，将被作为第三个参数传递给回调函数。
		array_walk($fielddata, array($this, 'add_special_char'));
		array_walk($valuedata, array($this, 'escape_string'));
		$field = implode (',', $fielddata);
		$value = implode (',', $valuedata);
		
		$cmd = $replace ? 'REPLACE INTO' : 'INSERT INTO';
		$sql = $cmd.' `'.$this->config['database'].'`.`'.$table.'`('.$field.') VALUES ('.$value.')';
		$return = $this->execute($sql);
		return $return_insert_id ? $this->insert_id() : $return;
	}
	
	/**
	 * 获取最后一次添加记录的主键号
	 * @return int 
	 */
	public function insert_id() {
		return mysql_insert_id($this->link);
	}
	
	/**
	 * 执行更新记录操作
	 * @param $data 		要更新的数据内容，参数可以为数组也可以为字符串，建议数组。
	 * 						为数组时数组key为字段值，数组值为数据取值
	 * 						为字符串时[例：`name`='php',`hits`=`hits`+1]。
	 *						为数组时[例: array('name'=>'pms','password'=>'123456')]
	 *						数组可使用array('name'=>'+=1', 'base'=>'-=1');程序会自动解析为`name` = `name` + 1, `base` = `base` - 1
	 * @param $table 		数据表
	 * @param $where 		更新数据时的条件
	 * @return boolean
	 */
	public function update($data, $table, $where = ''){
		if($where == '' || $table == ''){
			return false;
		}
		$where = ' WHERE '.$where;
		$field = '';
		if(is_string($data) && $data != ''){
			$field = $data;
		} elseif (is_array($data) && count($data) > 0) {
			$fields = array();
			foreach($data as $k => $v){
				switch (substr($v, 0, 2)){
					case '+=':
						$v = substr($v, 2);
						if(is_numeric($v)){
							$fields[] = $this->add_special_char($k).'='.$this->add_special_char($v).'+'.$this->escape_string($v, '',false);
						} else {
							continue;
						}
						break;
					case '-=':
						$v = substr($v,2);
						if (is_numeric($v)) {
							$fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '',false);
						} else {
							continue;
						}
						break;
					default:
						$fields[] = $this->add_special_char($k).'='.$this->escape_string($v);
						
				}
			}
			$fields = implode(',', $fields);
		} else{
			return false;
		}
		
		$sql = ' UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$fields.$where;
		return $this->execute($sql);
	}
	
	/**
	 * 执行删除记录操作
	 * @param $table 		数据表
	 * @param $where 		删除数据条件,不充许为空。
	 * 						如果要清空表，使用empty方法
	 * @return boolean
	 */
	public function delete($table, $where){
		if($where =='' || $table == ''){
			return false;
		}
		$where = ' WHERE '.$where;
		$sql = 'DELETE FROM `'.$this->config['database'].'`.`'.$table.'`'.$where;
		return $this->execute($sql);
	}
	
	public function close(){
		if(is_resource($this->link)){
			@mysql_close($this->link);
		}
	}
		
	/*
	 * 版本
	 */
	private function version(){
		if(!is_resource($this->link)){
			$this->connect();
		}
		return mysql_get_server_info($this->link);
	}
	

	/*
	 * 错误提示
	 */
	private function halt($message = '', $sql = ''){
		if($this->config['debug']){
			$errormsg = "<b>MySQL Query : </b> $sql <br /><b> MySQL Error : </b>".$this->error()." <br /> <b>MySQL Errno : </b>".$this->errno()." <br /><b> Message : </b> $message <br />";
			$msg = $errormsg;
			echo '<div style="font-size:12px;text-align:left; border:1px solid #9cc9e0; padding:1px 4px;color:#000000;font-family:Arial, Helvetica,sans-serif;"><span>'.$msg.'</span></div>';
			exit;
		} else {
			return false;
		}
	}
	
	private function error(){
		return @mysql_error($this->link);
	}
	
	private function errno(){
		return intval(@mysql_errno($this->link));
	}
	
	/**
	 * 对字段两边加反引号，以保证数据库安全
	 * @param $value 数组值
	 */
	private function add_special_char(&$value){
		//不处理*,sql方法
		if('*' == $value || false !== strpos($value,'(') || false !== strpos($value,'.')|| false !== strpos ( $value, '`')){
		} else {
			$value = '`'.trim($value).'`';
		}
		return $value;
	}
	
	/**
	 * 对字段值两边加引号，以保证数据库安全
	 * @param $value 数组值
	 * @param $key 数组key
	 * @param $quotation 
	 */
	private function escape_string(&$value, $key='', $quotation = 1) {
		if($quotation){
			$q = '\'';
		} else {
			$q = '';
		}
		$value = $q.$value.$q;
		return $value;
	}
}